<?php
// +----------------------------------------------------------------------
// | OneChat [ 做实用的网站微信内容交互管理平台 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016 http://www.juexin.pro All rights reserved.
// +----------------------------------------------------------------------
// | Author: Tealun Du <tealun@guilins.com> <http://www.tealun.com>
// +----------------------------------------------------------------------

namespace Admin\Event;

use Think\Controller;
use Wechat\Api\WechatApi;

/**
 * 微信回复流程逻辑
 * data采用统一的数据格式:
 *              array(
 *                  ‘openid’,//用户openid，此项已在微信模块的ReplyEvent中添加，可以不用考虑
 *                   'module',//处理模块，这个也可以不用管。
 *                   'action_name',//这个是本类中的方法，必须有
 *                   'action_data',//这个是方法需要的参数，根据业务逻辑可以不设置
 *                  )
 */
class ReplyEvent extends Controller {

    private $data = array();
    private $wechat;

    protected function _initialize() {
        /* 读取站点配置 */
        $config = api('Config/lists');
        C($config); //添加配置
        $this->wechat = new WechatApi();
    }
    /**
     * 回复微信流程
     *
     * @param $qrCode
     *
     * @return array
     */
    public function reply($data) {

        $this->data = $data;
        switch($data['action_name']){
            case'keyword':
                $reply = $this->keyword();
                break;
            case"text":
                $reply = $this->text();
                break;
            case"category":
                $reply = $this->category();
                break;
            case"document":
                $reply = $this->document();
                break;
            case"author":
                $reply = $this->author();
                break;
            case"service":
                $reply = $this->service();
                break;
            case"suggest":
                $reply = $this->suggest();
                break;
            case"albumCategory":
                $reply = $this->albumCategory();
                break;
            case"album":
                $reply = $this->album();
                break;
            default:
                $reply = set_response_arr('回复项目配置错误，请联系管理员指定正确回复项目类型');
        }

        return $reply;
    }

    /**
     * 回复选择触发关键词
     * @param $keyword
     * @return array
     */
    private function keyword(){
        $keyword = $this->data['action_data'];
        return $this->keywordMatch($keyword);
    }

    /**
     * 获取关键词所属分组
     * 关键词与关键词组为多对多关系，当一个关键词有多个关键词组对应时，返回给客户对应有几个关键词组名并缓存
     * 客户可通过该缓存回复相应数字回复不同的关键词组对应内容
     *
     * @param array $groupIds 找到的关键词组ID数组
     */
    private function keywordMatch($keyword) {

        $Group = M('TchatKeywordGroup');
        $map['keywords'] = array( 'like' , '%' . $keyword . '%' );
        $map['status'] = array( 'eq' , '1' );
        $map['deadline'] = array('gt',1);
        $map['deadline'] = array('lt',time());
        $name = $Group->where($map)->getField('id,name',true);

        if ( !empty( $name ) ) {
            $i = 1;
            $contentlist = '';
            foreach ( $name as $k => $v ) {
                $contentlist .= $i . ")." . $v . "\n";
                $listCache[$i] = $k;
                $i++;
            }
            $i--;

            /* 当只找到一条记录符合时，直接回复该关键词组对应的回复 */
            if ( $i == 1 ) {
                $kid = (int)arr2str(array_keys($name));

                $map['id'] = $kid;
                $rs = $Group->where($map)->find();

                unset( $listCache);//清除缓存变量
                //判断是否过期，0为长期有效，过期则回复过期回复文字，有效则进入相应模型查找回应内容。
                if (0 < $rs['deadline'] && $rs['deadline'] < time()) {
                    $dead_text =  is_numeric($rs['dead_text'])
                        ?M('Tchat_text')->where('`id`="' . $rs['dead_text'] . '"')->getField('content')
                        :$rs['dead_text'];
                    return $reply = set_response_arr($dead_text);
                }
                $this->data['action_data'] = $rs['action_data'];
                //直接回复该条对应的回复调用内容
                $reply = M('TchatReplyFlow')->where('`id` = '.$rs['flow_id'])->find();
                if(!$reply){
                    return set_response_arr('关键词设置不正确，请联系管理员');
                }

                if($reply['module'] == 'Admin'){
                    return $this->$reply['action_name']();
                }else{
                    return A($reply['module'].'/'.$reply['controller'],$reply['layer'])->reply($this->data);
                }

                /*找到多个符合的记录时，提供选择并缓存*/
            } else {
                $content = "[愉快]为您找到" . $i . "个结果：";
                $content.="\n--------------------\n";
                $content.= $contentlist ;
                $content.="\n--------------------\n";
                $content.="回复相应序号查看详情。\n ";
                $content.="(1分钟内有效)\r(づ￣ ³￣)づ";
                unset( $i );

                $openId = $this->data['openid'];


                S($openId , array(
                    'action' => array(
                        'controller' => "Admin/Cache,Event" , //需要后续处理的控制器及命名空间
                        'method' => 'reply' , //需要后续处理的公共方法
                    ) ,
                    'needs' => array(
                        'action_name' => 'listCache', //取缓存数组的键名作为关键字数组
                        'keywords' => array_keys($listCache),  //取缓存数组的键名作为关键字数组
                        'listCache' => $listCache //缓存查询后的数组内容 缓存对应列表序号关键字的group_id字段值，
                    ) ,
                ) , 60);


                return set_response_arr($content);
            }
        } else {
            return false;
        }
    }

    /**
     * 回复文本
     * @return array
     */
    private function text(){
        $text = $this->data['action_data'];
        if(is_numeric($text)){
            $text = get_tchat_text($text);
        }

        return set_response_arr($text);
    }

    /**
     * 获取指定分类文章
     * @return array
     */
    private function category(){

        $cateIdArr = str2arr($this->data['action_data']);
        //查找子分类

        $subIds = $this->findSubCate($cateIdArr);

        //有子分类就合并分类数组，并去重复
        if($subIds){
            $cateIdArr = array_merge($cateIdArr,$subIds);
        }

        $map['category_id'] = array( 'in' , $cateIdArr );//在指定目录及其子目录下的文档
        $map['status'] = array( 'eq' , 1 ); //状态为启用
        $map['pid'] = array( 'eq' , 0 ); //不获取子文档，只获取指定分类下的根文档

        $order = array( 'level' => 'desc' , 'create_time' => 'desc' );

        /*根据条件取出相应记录，限制80条，即10页内容*/
        $news = M('Document')->where($map)->order($order)->getField('id,title,description,cover_id,index_pic,link_id,level,model_id' , 80);
        if(!$news){
            //到事件设置中查找“分类下无文章”时的回复流程
            $flow = M('TchatEvents')->where('`id` = "5"')->getField('id,flow_id,action_data');
            //将该事件中设置的回复参数赋值给本类的data变量
            $this->data['action_data'] = $flow[5]['action_data'];
            //查找到相应的回复处理流程
            $reply = M('TchatReplyFlow')->where('`id` = '.$flow[5]['flow_id'])->find();
            //判断该流程是否是本模块下本类中的流程
            if($reply['module'] == 'Admin'){
                return $this->$reply['action_name']();
            }else{
                //非本类流程，跨模块调用回复
                return A($reply['module'].'/'.$reply['controller'],$reply['layer'])->reply($this->data);
            }
        }
        $this->rebuildNews($news,'Article');
        return set_response_arr($news,'news');
    }

    /**
     * 查找指定分类的子分类
     *
     * @param $catIds
     * @return array|mixed
     */
    private function findSubCate($catIds){

        foreach($catIds as $id){
            $map['pid'] = array('eq',$id);
            $re = M('Category')->where($map)->getField('id' , true);
        }
        if($re){
            $arr = $this->findSubCate($re);
            if($arr){
                $re = array_merge($re,$arr);
            }
        }
        return $re;
    }

    /**
     * 获取指定文章
     * @return array
     */
    private function document(){
        $idArr = str2arr($this->data['action_data']);
        $map['id'] = array( 'in' , $idArr );//在指定目录及其子目录下的文档
        $map['status'] = array( 'eq' , 1 ); //状态为启用
        $map['pid'] = array( 'eq' , 0 ); //不获取子文档，只获取指定分类下的根文档
        $order = array( 'level' => 'desc' , 'create_time' => 'desc' );

        /*根据条件取出相应记录，限制80条，即10页内容*/
        $news = M('Document')->where($map)->order($order)->getField('id,title,description,cover_id,index_pic,link_id,level,model_id');
        if(!$news){
            return set_response_arr("我家有一只猫，可爱的很，但是经常犯糊涂，就像小编一样，看，小编这会儿就犯糊涂了，要么是把要回复给你的东西放错位置了，要么就是弄丢了。\r\n\r\n这可如何是好呢？好蓝瘦~");
        }
        $this->rebuildNews($news,'Article');
        return set_response_arr($news,'news');
    }

    /**
     * 获取指定作者文章
     * @return array
     */
    private function author(){
        $map['uid'] = $this->data['action_data'];//指定作者
        $map['status'] = array( 'eq' , 1 ); //状态为启用
        $map['pid'] = array( 'eq' , 0 ); //不获取子文档，只获取指定分类下的根文档
        $map['deadline'] = array( 'NOT BETWEEN ' , array( 1 , time() ) ); //截止日期为0或大于现在时间的

        $order = array( 'level' => 'desc' , 'create_time' => 'desc' );

        /*根据条件取出相应记录，限制80条，即10页内容*/
        $news = M('Document')->where($map)->order($order)->getField('id,title,description,cover_id,index_pic,link_id,level,model_id' , 80);
        $this->rebuildNews($news,'Article');
        return set_response_arr($news,'news');
    }

    /**
     * 转发客服消息
     * @return array
     */
    private function service(){

        if(check_wechat_service() && check_wechat_rz()){
            $kfList = get_wechat_service();
            $online = get_wechat_online_service();
            if(empty($online['kf_online_list'])){
                $content = "很抱歉，当前没有在线客服，请致电联系我们。\n";
                $content .= "---------------------\n";
                $content .= "客服电话：".C('COMPANY_TELEPHONE');
                $content .= "\n---------------------";
            }else{
                //组织客服缓存
                $data = array(
                    'action' => array(
                        'controller' => "Cache,Logic" , //需要后续处理的控制器及命名空间
                        'method' => 'serviceCache' , //需要后续处理的公共方法
                    )
                );

                if($this->data['action_data']){//设置了指定客服
                    $name = strtolower($this->data['action_data']);
                    foreach($kfList['kf_list'] as $value){
                        if(strtolower($value['kf_nick']) === $name){
                            foreach($online['kf_online_list'] as $kf){
                                if($value['kf_id'] == $kf['kf_id']){
                                    $content = "您好，专属客服“".$value['kf_nick']."”为您服务\n";
                                    $content .= "---------------------\n";
                                    $content .= "请在2分钟内回复并简短描述您的问题。";
                                    $data['needs']=array(
                                        'service'=>$value['kf_account']
                                    );
                                    break;
                                }
                            }
                            if(!isset($content)){
                                $content = "您好，专属客服当前不在线，已帮您转接其他客服。\n";
                                $content .= "---------------------\n";
                                $content .= "请在2分钟内回复并简短描述您的问题。";
                            }
                            break;
                        }
                    }

                }else{//没有设置指定客服
                    $content = "您好，您已接入客服系统\n";
                    $content .= "---------------------\n";
                    $content .= "请在2分钟内回复并简短描述您的问题。";
                }
                //缓存客服数据
                $openId = $this->data['openid'];
                S($openId,$data,120);
            }

        }else{//没有开通多客服系统
            $content = "很抱歉，由于目前我们还未开通客服系统，请致电我们。\n";
            $content .= "---------------------\n";
            $content .= "客服电话：".C('COMPANY_TELEPHONE');
            $content .= "\n--------------------";
        }
        return set_response_arr($content,'text');
    }

    /**
     * 收集客户建议
     * @return array
     */
    private function suggest(){

        //$openid = $this->data['openid'];

        return set_response_arr('请回复您的建议');
    }

    /**
     * 获取指定分类文章
     * @return array
     */
    private function albumCategory(){

        $cateId = $this->data['action_data'];

        $map['cat_id'] = array( 'eq' , $cateId );//在指定目录及其子目录下的文档
        $map['status'] = array( 'eq' , 1 ); //状态为启用

        $order = array( 'sort' => 'desc' , 'create_time' => 'desc' );

        /*根据条件取出相应记录，限制80条，即10页内容*/
        $news = M('TchatAlbum')->where($map)->order($order)->getField('id,title,description,cover_id,link_id' , 80);
        if(!$news){
            //到事件设置中查找“分类下无文章”时的回复流程
            $flow = M('TchatEvents')->where('`id` = "5"')->getField('id,flow_id,action_data');
            //将该事件中设置的回复参数赋值给本类的data变量
            $this->data['action_data'] = $flow[5]['action_data'];
            //查找到相应的回复处理流程
            $reply = M('TchatReplyFlow')->where('`id` = '.$flow[5]['flow_id'])->find();
            //判断该流程是否是本模块下本类中的流程
            if($reply['module'] == 'Admin'){
                return $this->$reply['action_name']();
            }else{
                //非本类流程，跨模块调用回复
                return A($reply['module'].'/'.$reply['controller'],$reply['layer'])->reply($this->data);
            }
        }
        $this->rebuildNews($news,'Album');
        return set_response_arr($news,'news');
    }

    /**
     * 获取指定相册
     * @return array
     */
    private function album(){

        $idArr = str2arr($this->data['action_data']);
        $map['id'] = array( 'in' , $idArr );//在指定目录及其子目录下的文档
        $map['status'] = array( 'eq' , 1 ); //状态为启用

        $order = array( 'sort' => 'desc' , 'create_time' => 'desc' );

        /*根据条件取出相应记录*/
        $news = M('TchatAlbum')->where($map)->order($order)->getField('id,title,description,cover_id,link_id');
        if(!$news){
            return set_response_arr("我家有一只猫，可爱的很，但是经常犯糊涂，就像小编一样，看，小编这会儿就犯糊涂了，要么是把要回复给你的东西放错位置了，要么就是弄丢了。\r\n\r\n这可如何是好呢？好蓝瘦~");
        }
        $this->rebuildNews($news,'Album');
        return set_response_arr($news,'news');
    }

    private function rebuildNews(&$news,$modelName='Article'){
        foreach($news as $new){
            $news[$new['id']]['modelName'] = $modelName;
        }
    }
}
